#region imported Namespaces
using System;
using System.Collections;
using System.Data;
using System.Data.SqlClient;
using System.Text;

using BO = PHSRAG.Insight21.BusinessObjects;
using DataAccess = PHSRAG.Utility.DataAccess;
using ICachePolicy = PHSRAG.Insight21.Policy.ICachePolicy;
using SearchCriteria = PHSRAG.Insight21.SearchContext.SearchCriteria;
#endregion

namespace PHSRAG.Insight21.Personnel
{
	#region Class Monlthly labor distributions
	/// <summary>
	/// The MonthlyLaborDistributions object supports loading of distribution information
	/// for one person to date on one fund (or) personnel who have been paid on given account or fund 
	/// (or) all the people paid on all the funds there are in a given date range (or)
	/// all the people paid to date on funds that the user has access to see
	/// It also exposes methods to support sorting and searching on the retrieved data.
	/// </summary>
	public class MonthlyLaborDistributions : BO.BusinessObject
	{
		#region Constants
		private const string	MonthlyLaborDistributionsKey	= "MonthlyLaborDistributions_2D228A70-B5FF-4aa6-ACEB-89514B92BC38";
		private const string	DefaultSortColumn			= "LastName";
		private const int		DistribTableIndex			= 0;
		#endregion

		#region Instance Variables
		private Hashtable		monthlyLaborDistributionMap	= new Hashtable();
		private string			sortColumn				= DefaultSortColumn;
		private string			currentDataTableName	= Constants.OriginalDataTableName;
		private bool			sortAscending			= true;
		private string			headerDataTableName		= "HeaderTable";
		private string			detailsDatesDataTableName = "DetailsDatesDataTableName";
		private string			totalsDatesDataTableName = "TotalsDatesDataTableName";

		#endregion

		#region Constructor
		/// <summary>
		/// Intialize the base class with the prevalent cache policy
		/// </summary>
		/// <param name="cachePolicy">The prevalent cache policy</param>
		public MonthlyLaborDistributions():base(null)
		{
		}
		#endregion

		#region Public Properties
		/// <summary>
		/// Get the key to be used in all caching operations for this instance of the object.
		/// </summary>
		public static string CacheKey	{ get { return MonthlyLaborDistributionsKey; } }

		/// <summary>
		/// Get the total number of Labor distribution rows in the data container.
		/// Returns 0 if there is no data in the data container
		/// </summary>
		public int Count
		{
			get 
			{
				return (DataContainer.Tables.Count == 0)
					  ? 0 : DataContainer.Tables[currentDataTableName].Rows.Count; }
		}

		/// <summary>
		/// Get the table name of the active table in the data container
		/// This will be used for selective downloading of data into reports
		/// </summary>
		public string CurrentDataTableName
		{
			get { return currentDataTableName;}
		}

		/// <summary>
		/// Get the detail end date
		/// Return today if there is no detail end date
		/// </summary>
		public DateTime DetailEndDate
		{
			get
			{
				object detailEndDate = DataContainer.Tables[detailsDatesDataTableName].Rows[0]["MonthlyDetailEndDate"];
				return (detailEndDate == DBNull.Value) ? DateTime.Now : Convert.ToDateTime(detailEndDate.ToString());
			}
		}

		/// <summary>
		/// Get the totals start date
		/// Return 1/1/1900 if there is no detail start date
		/// </summary>
		public DateTime DetailStartDate
		{
			get
			{
				object detailStartDate = DataContainer.Tables[detailsDatesDataTableName].Rows[0]["MonthlyDetailStartDate"];
				return (detailStartDate == DBNull.Value) ? new DateTime(1900, 1, 1) : Convert.ToDateTime(detailStartDate.ToString());
			}
		}

		/// <summary>
		/// Get the table name that contains the detail dates columns
		/// </summary>
		public string DetailsDatesDataTableName
		{
			get { return detailsDatesDataTableName;}
		}

		/// <summary>
		/// Gets the header text associated with the month1 column
		/// </summary>
		public string Month1HeaderText
		{
			get
			{
				object o = DataContainer.Tables[headerDataTableName].Rows[0]["Month1"];
				return (o == DBNull.Value) ? string.Empty : (string)o;
			}
		}

		/// <summary>
		/// Gets the header text associated with the month2 column
		/// </summary>
		public string Month2HeaderText
		{
			get
			{
				object o = DataContainer.Tables[headerDataTableName].Rows[0]["Month2"];
				return (o == DBNull.Value) ? string.Empty : (string)o;
			}
		}
		/// <summary>
		/// Gets the header text associated with the month3 column
		/// </summary>
		public string Month3HeaderText
		{
			get
			{
				object o = DataContainer.Tables[headerDataTableName].Rows[0]["Month3"];
				return (o == DBNull.Value) ? string.Empty : (string)o;
			}
		}
		/// <summary>
		/// Gets the header text associated with the month4 column
		/// </summary>
		public string Month4HeaderText
		{
			get
			{
				object o = DataContainer.Tables[headerDataTableName].Rows[0]["Month4"];
				return (o == DBNull.Value) ? string.Empty : (string)o;
			}
		}
		/// <summary>
		/// Gets the header text associated with the month5 column
		/// </summary>
		public string Month5HeaderText
		{
			get
			{
				object o = DataContainer.Tables[headerDataTableName].Rows[0]["Month5"];
				return (o == DBNull.Value) ? string.Empty : (string)o;
			}
		}
		/// <summary>
		/// Gets the header text associated with the month6 column
		/// </summary>
		public string Month6HeaderText
		{
			get
			{
				object o = DataContainer.Tables[headerDataTableName].Rows[0]["Month6"];
				return (o == DBNull.Value) ? string.Empty : (string)o;
			}
		}
		/// <summary>
		/// Gets the header text associated with the month7 column
		/// </summary>
		public string Month7HeaderText
		{
			get
			{
				object o = DataContainer.Tables[headerDataTableName].Rows[0]["Month7"];
				return (o == DBNull.Value) ? string.Empty : (string)o;
			}
		}
		/// <summary>
		/// Gets the header text associated with the month8 column
		/// </summary>
		public string Month8HeaderText
		{
			get
			{
				object o = DataContainer.Tables[headerDataTableName].Rows[0]["Month8"];
				return (o == DBNull.Value) ? string.Empty : (string)o;
			}
		}
		/// <summary>
		/// Gets the header text associated with the month9 column
		/// </summary>
		public string Month9HeaderText
		{
			get
			{
				object o = DataContainer.Tables[headerDataTableName].Rows[0]["Month9"];
				return (o == DBNull.Value) ? string.Empty : (string)o;
			}
		}
		/// <summary>
		/// Gets the header text associated with the month10 column
		/// </summary>
		public string Month10HeaderText
		{
			get
			{
				object o = DataContainer.Tables[headerDataTableName].Rows[0]["Month10"];
				return (o == DBNull.Value) ? string.Empty : (string)o;
			}
		}
		/// <summary>
		/// Gets the header text associated with the month11 column
		/// </summary>
		public string Month11HeaderText
		{
			get
			{
				object o = DataContainer.Tables[headerDataTableName].Rows[0]["Month11"];
				return (o == DBNull.Value) ? string.Empty : (string)o;
			}
		}
		/// <summary>
		/// Gets the header text associated with the month12 column
		/// </summary>
		public string Month12HeaderText
		{
			get
			{
				object o = DataContainer.Tables[headerDataTableName].Rows[0]["Month12"];
				return (o == DBNull.Value) ? string.Empty : (string)o;
			}
		}
		/// <summary>
		/// Get the table name that contains the header columns
		/// </summary>
		public string HeaderDataTableName
		{
			get { return headerDataTableName;}
		}

		/// <summary>
		/// Get the sort sequence.
		/// </summary>
		public bool SortAscending
		{
			get { return sortAscending; }
		}

		/// <summary>
		/// Get the name of the sort column.
		/// </summary>
		public string SortColumn
		{
			get { return sortColumn; }
		}

		/// <summary>
		/// Get the table name that contains the total dates columns
		/// </summary>
		public string TotalsDatesDataTableName
		{
			get { return totalsDatesDataTableName;}
		}

		/// <summary>
		/// Get the totals end date
		/// Return today if there is no totals end date
		/// </summary>
		public DateTime TotalsEndDate
		{
			get
			{
				object totalsEndDate = DataContainer.Tables[totalsDatesDataTableName].Rows[0]["TotalsEndDate"];
				return (totalsEndDate == DBNull.Value) ? DateTime.Now: Convert.ToDateTime(totalsEndDate.ToString());
			}
		}

		/// <summary>
		/// Get the totals start date
		/// Return 1/1/1900 if there is no totals start date
		/// </summary>
		public DateTime TotalsStartDate
		{
			get
			{
				object totalsStartDate = DataContainer.Tables[totalsDatesDataTableName].Rows[0]["TotalsStartDate"];
				return (totalsStartDate == DBNull.Value) ? new DateTime(1900, 1, 1) : Convert.ToDateTime(totalsStartDate.ToString());
			}
		}
		#endregion

		#region BusinessObject Methods
		/// <summary>
		/// Load the Labor distribution data depending on the context in which the user is requesting the data.
		/// The data will be loaded either in context with the Personnel Module or the agreements module
		/// Sort the laoded data on the default sort column
		/// For the load the domain user id is mandatory.
		/// </summary>
		/// <param name="connectionString">Database connection string</param>
		/// <param name="args">There are different contexts on which the data has to be loaded
		/// The different scenarios and the mandatory args are listed below
		/// <list type="bullet">
		/// <item><description>DomainUserID is mandatory in all scenarios</description></item>
		/// </list>
		/// </param>
		public override void Load(string connectionString, params object[] args)
		{
			try 
			{
				SearchCriteria searchCriteria = (SearchCriteria) args[0];
				object domainUserID = searchCriteria[InsightUtilities.Constants.DomainUserIDKey];
				if ((domainUserID == null) || ((string)domainUserID == string.Empty || (string)domainUserID == "0"))
					throw new Exception("Labor Distribution load requires a domain user ID");

				DataContainer = DataAccess.GetDataSet(
                    connectionString
					,"GetMonthlyLaborDistributions"//Constants.GetMonthlyLaborDistributionsSPROCName
					,Utility.DataAccess.BuildSqlParameterArray
					("@domainUserId", SqlDbType.Int, Convert.ToInt32(domainUserID)
						,"@piId", SqlDbType.Int, searchCriteria["PI"]
						,"@lastName", SqlDbType.VarChar, searchCriteria["EmployeeLastName"]
						,"@firstName", SqlDbType.VarChar, searchCriteria["EmployeeFirstName"]
						,"@fundNumber", SqlDbType.VarChar, searchCriteria["FundNumber"]
						,"@payStartDate", SqlDbType.DateTime, searchCriteria["PayDateFrom"]
						,"@payEndDate", SqlDbType.DateTime, searchCriteria["PayDateTo"]
						,"@monthlyDetailEndDate", SqlDbType.DateTime, (string)args[1]));

				if (DataContainer.Tables.Count == 4)
					DataContainer.Tables[DistribTableIndex].TableName	= Constants.OriginalDataTableName;
				else
					throw new Exception(@"No monthly distribution data found for the user");

				DataContainer.Tables[1].TableName = HeaderDataTableName;
				DataContainer.Tables[2].TableName = DetailsDatesDataTableName;
				DataContainer.Tables[3].TableName = TotalsDatesDataTableName;

				ProcessSort();
			}
			catch(Exception ex)
			{
				throw new Exception(Utility.ExceptionReport.GetExceptionInfo(ex,false));
			}
		}
		#endregion

		#region Public Methods
		/// <summary>
		/// Get the list of MonthlyLaborDistribution objects bound by a start and end index. 
		/// These indeces are into the list of Monlthly labor distributions that was loaded during the 
		/// Load() method execution into the data container. Typically, the start index is on 
		/// a "page" boundary, where the "page" referes to a datagrid page.
		/// A Hashtable of ArrayList objects is maintained using the start index as the key. 
		/// This allows retrieval of the set of MonthlyLaborDistribution objects associated with that 
		/// index, thereby directly supporting random access based the page index.
		/// </summary>
		/// <param name="startIndex">Index within the Labor Distribution list to begin at</param>
		/// <param name="count">Total number of MonthlyLaborDistribution objects to load</param>
		/// <returns>The list of MonthlyLaborDistribution objects</returns>
		public ArrayList GetMonthlyLaborDistributionList(int startIndex, int count)
		{
			ArrayList monthlyLaborDistributionList = monthlyLaborDistributionMap[startIndex] as ArrayList;
			if (monthlyLaborDistributionList == null)
			{
				monthlyLaborDistributionList = new ArrayList();
				DataTable distributionTable = DataContainer.Tables[currentDataTableName];
				for (int indexCount = startIndex, end = Math.Min(indexCount + count, distributionTable.Rows.Count); indexCount < end; ++indexCount)
					monthlyLaborDistributionList.Add(new MonthlyLaborDistribution(CachePolicy,distributionTable.Rows[indexCount]));
				monthlyLaborDistributionMap[startIndex] = monthlyLaborDistributionList;
			}
			return monthlyLaborDistributionList;
		}

		/// <summary>
		/// Search the DataContainer for rows which match the specified search criteria.
		/// Two DataTables are maintained within the DataContainer; a full-complement DataTable and a filtered one.
		/// This allows filtering without having to hit the database. If a filter is in
		/// effect, we simply set the value of the currentTableName to Constants.FilteredDataTableName so that the
		/// GetLaborDIstributionList() method may retreive from the appropriate DataTable.
		/// </summary>
		/// <param name="searchCriteria">The search criteria instance picked from the search context</param>
		/// <param name="detailEndDate">The detail end date.</param>
		/// <remarks>True if the search criteria did any filtering; false otherwise</remarks>
		public bool Search(SearchCriteria searchCriteria, string detailEndDate)
		{
			monthlyLaborDistributionMap.Clear();
			Load(Utility.DataAccess.ConnectionString, searchCriteria, detailEndDate);
			return true;

		}
		/// <summary>
		/// Sort the list of Monlthly labor distributions by the speicified column.
		/// If the column is to be sorted is the same as what was last sorted on, the sort sequence is toggled. Else, the
		/// sort sequence is set to ascending.
		/// </summary>
		/// <param name="columnName">Column to sort by</param>
		public void Sort(string columnName)
		{
			monthlyLaborDistributionMap.Clear();

			sortAscending = (sortColumn == columnName) ? !sortAscending : true;
			sortColumn = columnName;
			
			ProcessSort();			
		}
		#endregion

		#region Private methods
		/// <summary>
		/// Sorts the current data table on the sortColumn instance variable
		/// in the order specified by the sortOrder instance variable
		/// </summary>
		private void ProcessSort()
		{
			DataTable distributionTable = DataContainer.Tables[currentDataTableName];
			DataView distributionView = distributionTable.DefaultView;
			distributionView.Sort = string.Format("{0} {1}", 
				sortColumn, sortAscending ? Constants.SortOrderAscending : Constants.SortOrderDescending);

			DataTable sortedDataTable = distributionTable.Clone();
			foreach (DataRowView distributionRowView in distributionView)
				sortedDataTable.ImportRow(distributionRowView.Row);

			if(DataContainer.Tables.Contains(currentDataTableName))
				DataContainer.Tables.Remove(currentDataTableName);
			
			DataContainer.Tables.Add(sortedDataTable);
		}
		#endregion
	}
	#endregion
}